package com.durian.finance.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.durian.affairs.api.RemoteCReceiptPlanService;
import com.durian.affairs.api.domain.CwReceiptPlan;
import com.durian.common.core.web.controller.BaseController;
import com.durian.common.core.web.domain.AjaxResult;
import com.durian.common.core.web.page.TableDataInfo;
import com.durian.common.security.annotation.RequiresPermissions;
import com.durian.common.security.utils.SecurityUtils;
import com.durian.finance.service.ICfContractService;
import com.durian.finance.service.IFkBusinessCreditService;
import com.durian.finance.service.IJrFactoringService;
import com.durian.finance.service.IJrProductService;
import com.durian.financial.api.domain.*;
import com.durian.financial.api.domain.enums.ContractTypeEnum;
import com.durian.financial.api.domain.vo.ChooseContractVO;
import com.durian.financial.api.domain.vo.ContractVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 租约保理申请Controller
 * 
 * @author durian
 * @date 2022-06-27
 */
@RestController
@RequestMapping("/factoring")
public class JrFactoringController extends BaseController
{
    @Autowired
    private IJrFactoringService jrFactoringService;

    @Autowired
    private ICfContractService cfContractService;

    @Autowired
    private IJrProductService jrProductService;

    @Autowired
    private IFkBusinessCreditService businessCreditService;

    @Resource
    private RemoteCReceiptPlanService receiptPlanService;


    /**
     * 获取应收租约保理Map
     *
     * @return
     */
    @RequiresPermissions("finance:product:list")
    @GetMapping("/factoringApplyMap")
    public AjaxResult getProductMap(){

        Map<Long, JrProduct> productMap = jrFactoringService.getProductMap(3);
        return AjaxResult.success(productMap);
    }


    /**
     * 获取符合保理申请明细的租房合同列表
     *
     * @param vo
     * @return
     */
    @RequiresPermissions("finance:contract:list")
    @GetMapping("/listFactoringContract")
    public TableDataInfo listFactoringContract(ContractVO vo){

        startPage();
        List<CfContract> cfContracts = cfContractService.listFactoringContract(vo);
        return getDataTable(cfContracts);
    }

    /**
     * 根据合同和保理产品计算该合同的保理申请明细
     */
    @GetMapping("/contract")
    public AjaxResult chooseContract(ChooseContractVO vo){

        // 获取合同信息，租约保理详情在合同信息基础上
        CfContract contract = cfContractService.selectCfContractById(vo.getContractId());

        // 实例化租约保理详情对象
        JrFactoringDetail factoringDetail = new JrFactoringDetail();
        BeanUtil.copyProperties(contract,factoringDetail);

        // 根据合同id 和 合同类型获取对应计划
        List<CwReceiptPlan> receiptPlans = receiptPlanService.listReceiptPlanByContract(new ContractVO().setContractId(vo.getContractId()).setContractType(ContractTypeEnum.CF.getIndex())).getData();

        // 如果存在计划
        if (CollectionUtil.isNotEmpty(receiptPlans)){

            // 获取最小期数 开始日
            factoringDetail.setBorrowedStart(receiptPlans.get(0).getPaymentDaysBegin());

            // 获取最大期数 结束日
            factoringDetail.setBorrowedEnd(receiptPlans.get(receiptPlans.size() - 1).getPaymentDaysEnd());

            // 计算应收金额 = 所有 支付金额 相加
            BigDecimal sumMoney = BigDecimal.ZERO;
            for (CwReceiptPlan plan : receiptPlans) {
                sumMoney = sumMoney.add(plan.getPaymentAmount());
            }
            factoringDetail.setShouldMonthRent(sumMoney);

            // 计算借款周期 = 合同收款方式 * 记录总条数
            factoringDetail.setFactoringPeriod(contract.getPaymentType() * receiptPlans.size());

            // 获取对应产品 需要用到：授信额度
            JrProduct product = jrProductService.selectJrProductById(vo.getJrProductId());

            // 计算授信额度总金额 = 应收租约金额 * (授信额度 / 100) 需要：四舍五入
            factoringDetail.setFactoringCreditMoney(
                    sumMoney.multiply(product.getCreditLine()
                            .divide(new BigDecimal(100),2,BigDecimal.ROUND_HALF_UP))
                            .setScale(2,BigDecimal.ROUND_HALF_UP)
            );


            // 计算利息 = 授信额度总金额 * 月利率 * 月数 需要：四舍五入
            factoringDetail.setFactoringInterest(
                    factoringDetail.getFactoringCreditMoney()
                            .multiply(vo.getInterestRate()
                                    .divide(new BigDecimal(100 * 12),2,BigDecimal.ROUND_HALF_UP))
                                    .multiply(new BigDecimal(factoringDetail.getFactoringPeriod()))
                                    .setScale(2,BigDecimal.ROUND_HALF_UP)
            );

            // 计算服务费
            factoringDetail.setServiceFee(
                    factoringDetail.getFactoringCreditMoney()
                            .multiply(vo.getServiceFee()
                                    .divide(new BigDecimal(100 * 12),2,BigDecimal.ROUND_HALF_UP)
                                    .multiply(new BigDecimal(factoringDetail.getFactoringPeriod())).setScale(2,BigDecimal.ROUND_HALF_UP))
            );

            // 如果所选择产品存在分期期限 且 不是无限期 且
            if (Objects.nonNull(product.getInstalmentPeriod())
                    && !Objects.equals(-1L,product.getInstalmentPeriod()) && factoringDetail.getFactoringPeriod() > product.getInstalmentPeriod()){

                // 租约期限超过保理产品期限
                return AjaxResult.error("该合同剩余租期已经超过所选保理产品期限！");
            }

            return AjaxResult.success(factoringDetail);
        }

        return AjaxResult.error("该合同剩余未逾期房租租约金额为0，不可申请租约保理！");
    }


    /**
     * 保存
     *
     * @param saveFactoring
     * @return
     */
    @PostMapping
    public AjaxResult saveFactoring(@RequestBody @Validated JrFactoring saveFactoring){

        // 根据商户id获取 风控公寓授信对象
        FkBusinessCredit businessCredit = businessCreditService.getByBusinessId(38L);

        // 根据商户id 和 金融产品id查询，判断商户是否有授权该产品
        FkBusinessCreditSub businessCreditSub = businessCreditService.getSubByBusinessIdAndProductId(38L,saveFactoring.getJrProductId());

        if (Objects.isNull(businessCreditSub)){

            return AjaxResult.error("授信额度不足，请联系维数公寓客服：400-008-3363");
        }

        // 计算剩余总授信额度
        BigDecimal residueTotal;

        // 如果已用额度不为null && 已用额度不为0
        if (Objects.nonNull(businessCreditSub.getUsedCreditline()) && ! Objects.equals(businessCreditSub.getUsedCreditline(),BigDecimal.ZERO)){

            // 剩余额度 = 总额度 - 已用额度
            residueTotal = businessCreditSub.getTotalCreditline().subtract(businessCreditSub.getUsedCreditline());
        } else {

            // 剩余额度 = 总额度
            residueTotal = businessCreditSub.getTotalCreditline();
        }

        // 如果剩余额度 < 本次应收应收租约合计
        if (residueTotal.compareTo(saveFactoring.getRentMoney()) < 0){

            return AjaxResult.error("授信额度不足，请联系维数公寓客服：400-008-3363");
        }


        // 计算剩余月授信额度
        BigDecimal monthResidueTotal;

        // 如果月资金方额度不为null && 月资金方额度不为0
        if (Objects.nonNull(businessCreditSub.getMonthlyTotalCreditline()) &&
                ! Objects.equals(businessCreditSub.getMonthlyTotalCreditline(), BigDecimal.ZERO)){

            // 如果月已用额度不为null && 月已用额度不为0
            if (Objects.nonNull(businessCreditSub.getMonthlyUsedCreditline()) &&
                    ! Objects.equals(businessCreditSub.getMonthlyUsedCreditline(),BigDecimal.ZERO)){

                // 剩余月授信额度 = 月总额度 - 已使用额度
                monthResidueTotal = businessCreditSub.getMonthlyTotalCreditline().subtract(businessCreditSub.getMonthlyUsedCreditline());
            } else {

                // 月剩余额度 = 总额度
                monthResidueTotal = businessCreditSub.getMonthlyTotalCreditline();
            }

            // 如果月剩余额度 < 本次应收应收租约合计
            if (monthResidueTotal.compareTo(saveFactoring.getRentMoney()) < 0){

                return AjaxResult.error("授信额度不足，请联系维数公寓客服：400-008-3363");
            }

        } else {

            // 如果海链月授信额度不为 null && 海链月授信额度不为0
            if (Objects.nonNull(businessCredit.getHlMonthlyTotalCreditline()) &&
                    ! Objects.equals(businessCredit.getHlTotalCreditline(), BigDecimal.ZERO)){

                // 如果海链月已用授信额度不为 null && 海链月已用授信额度不为0
                if (Objects.nonNull(businessCredit.getHlMonthlyUsedCreditline())
                        && ! Objects.equals(businessCredit.getHlMonthlyUsedCreditline(),BigDecimal.ZERO)){

                    // 海链月剩余授信额度 = 月总额度 - 已用额度
                    monthResidueTotal = businessCredit.getHlMonthlyTotalCreditline().subtract(businessCredit.getHlMonthlyUsedCreditline());
                } else {

                    // 剩余额度 = 总额度
                    monthResidueTotal = businessCredit.getHlMonthlyTotalCreditline();
                }

                // 如果月剩余额度 < 本次应收应收租约合计
                if (monthResidueTotal.compareTo(saveFactoring.getRentMoney()) < 0){

                    return AjaxResult.error("授信额度不足，请联系维数公寓客服：400-008-3363");
                }
            }
        }

        // 计算已用授信额度
        BigDecimal hlUsedCreditline;

        // 如果已用授信额度不为null && 已用授信额度不为0
        if (Objects.nonNull(businessCredit.getHlUsedCreditline()) && ! Objects.equals(businessCredit.getHlUsedCreditline(), BigDecimal.ZERO)){

            // 已用授信额度 = 总授信额度 + 本次应收租约合计
            hlUsedCreditline = businessCredit.getHlUsedCreditline().add(saveFactoring.getRentMoney());
        } else {

            // 已用授信额度 = 本次应收租约合计
            hlUsedCreditline = saveFactoring.getRentMoney();
        }
        // 设置已用授信额度
        businessCredit.setHlUsedCreditline(hlUsedCreditline);


        // 如果月度授信额度不为null && 月度授信额度不为0
        if (Objects.nonNull(businessCredit.getHlMonthlyTotalCreditline()) &&
                ! Objects.equals(businessCredit.getHlMonthlyTotalCreditline(), BigDecimal.ZERO)){

            // 计算月度已用授信额度
            BigDecimal hlMonthUsedCreditline;

            // 如果月已用额度不为null && 月已用额度不为0
            if (Objects.nonNull(businessCredit.getHlMonthlyUsedCreditline()) &&
                    ! Objects.equals(businessCredit.getHlMonthlyUsedCreditline(),BigDecimal.ZERO)){

                // 新月已用额度 = 旧月已用额度 + 本次应收租约合计
                hlMonthUsedCreditline = businessCredit.getHlMonthlyUsedCreditline().add(saveFactoring.getRentMoney());
            } else {

                // 新月已用额度 = 本次应收租约合计
                hlMonthUsedCreditline = saveFactoring.getRentMoney();
            }
            businessCredit.setHlMonthlyUsedCreditline(hlUsedCreditline);

        }
        // 设置修改时间
        businessCredit.setUpdateTime(new Date());

        // 设置修改用户
        businessCredit.setUpdateUserid(SecurityUtils.getUserId());

        // 修改风控公寓授信主表
        businessCreditService.updateFkBusinessCredit(businessCredit);

        // 计算总资方已用额度
        BigDecimal usedTotal;

        // 如果已用授信额度不为null && 已用授信额度不为0
        if (Objects.nonNull(businessCreditSub.getUsedCreditline())
                && ! Objects.equals(businessCreditSub.getUsedCreditline(),BigDecimal.ZERO)){

            // 已用额度 = 总已用额度 + 应收租约合计
            usedTotal = businessCreditSub.getUsedCreditline().add(saveFactoring.getRentMoney());
        } else {

            // 为本次应收租约合计
            usedTotal = saveFactoring.getRentMoney();
        }
        businessCreditSub.setUsedCreditline(usedTotal);


        if (Objects.nonNull(businessCreditSub.getMonthlyCreditlineCount()) &&
                ! Objects.equals(businessCreditSub.getMonthlyTotalCreditline(),BigDecimal.ZERO)){

            // 计算月租金方已用额度
            BigDecimal usedMonth;

            // 如果月租金方已用额度不为null && 月租金方已用额度不为0
            if (Objects.nonNull(businessCreditSub.getMonthlyUsedCreditline()) &&
                    ! Objects.equals(businessCreditSub.getMonthlyUsedCreditline(), BigDecimal.ZERO)){

                usedMonth = businessCreditSub.getMonthlyUsedCreditline().add(saveFactoring.getRentMoney());
            } else {

                usedMonth = saveFactoring.getRentMoney();
            }
            businessCreditSub.setMonthlyUsedCreditline(usedMonth);
        }

        // 设置修改用户 与 修改时间
        businessCreditSub.setUpdateUserid(SecurityUtils.getUserId()).setUpdateTime(new Date());

        businessCreditService.updateFkBusinessCreditSub(businessCreditSub);

        // 保存
        jrFactoringService.saveFactoring(saveFactoring);

        return AjaxResult.success("申请成功！");
    }





}
